/*
 * raid.c
 *
 *  Created on: 25/09/2011
 *      Author: Romi - Luca
 */

#include <stdlib.h>

#include "raid.h"
#include "structRaid.h"




/**** Crear listas ****/

t_lista_discos *crear_lista_disco(){
	t_lista_discos *list_disco = malloc( sizeof(t_lista_discos) );
	return list_disco;
}

t_solicitud *crear_lista_solicitud(){
	t_solicitud *list_solicitud = malloc( sizeof(t_solicitud) );
	return list_solicitud;
}



/**** Agregar un nuevo disco ****/

t_lista_discos *agregar_disco(t_lista_discos *list_disco, t_nipc paquete){   /* El ppd nos dice que tiene un disco para agregar */

	t_lista_discos *aux;
	t_lista_discos *nuevo_disco = malloc( sizeof(t_lista_discos) );

	//desempaquetar(t_nipc paquete); Esta funcion me retorna un array con los datos

	nuevo_disco->id_disco = 0;
	nuevo_disco->estado_disco = 'N';
	nuevo_disco->cola_lectura = NULL;
	nuevo_disco->cola_escritura= NULL;
	nuevo_disco->escrituras_pendientes = 0;
	nuevo_disco->lecturas_pendientes = 0;
	nuevo_disco->sgte = NULL;


	if(list_disco == NULL){
		    list_disco = nuevo_disco;
    }else{
			aux = list_disco;
			while(aux->sgte != NULL){
				aux = aux->sgte;
			}
			aux->sgte = nuevo_disco;
			//sincronizar_disco();
		}

	return list_disco;
}



/**** Reasignar cola de lecturas de un disco que se está por remover ****/

void *reasignar_cola_lecturas(t_lista_discos *list_disco, t_solicitud *cola_lecturas){
	t_lista_discos *ptrD;
	t_solicitud *ptrS;

	ptrD = buscar_disco_menos_solicitado(list_disco);

	if(ptrD->cola_lectura == NULL){
		ptrD->cola_lectura = cola_lecturas;
	}else{
			ptrS = ptrD->cola_lectura;
			while(ptrS->sgte != NULL){
				ptrS = ptrS->sgte;
			}
			ptrS->sgte = cola_lecturas;
	}

	return 0;
}



/**** Busca el disco que menos lecturas pendientes tenga ****/

t_lista_discos *buscar_disco_menos_solicitado(t_lista_discos *list_disco){
	t_lista_discos *ptr;

	unsigned int min = list_disco->lecturas_pendientes;

	ptr = list_disco;

	while ( ptr->sgte !=NULL){
		if((ptr->lecturas_pendientes < min) && (ptr->estado_disco == 'S' )){
			min = ptr->lecturas_pendientes;
		}
		ptr= ptr->sgte;
	}
	return ptr;
}



/**** Agregar una nueva solicitud, tanto de lectura como de escritura ****/

t_solicitud *agregar_solicitud(t_solicitud *list_solicitud, t_nipc paquete){
	t_solicitud *aux;
	t_solicitud *nueva_solicitud = malloc( sizeof(t_solicitud) );

	//desempaquetar(t_nipc paquete) Esta funcion me retorna un array con los datos


	nueva_solicitud->sector_requerido = 0;
	nueva_solicitud->paquete = paquete;
	nueva_solicitud->sgte = NULL;

	if(list_solicitud == NULL){
			    list_solicitud = nueva_solicitud;
	    }else{
				aux = list_solicitud;
				while( aux->sgte != NULL ){
					aux= aux->sgte;
				}
				aux->sgte = nueva_solicitud;
			}

	return list_solicitud;
}



/**** Agrega una solicitud de lectura a todos los discos ****/

void agregar_escritura(t_lista_discos *list_disco, t_nipc paquete){
	t_lista_discos *ptr;

	ptr = list_disco;

	while (ptr->sgte !=NULL){
		agregar_solicitud(ptr->cola_escritura, paquete);
		ptr = ptr->sgte;
	}

	return;

}



/**** Remover disco ****/

void *remover_disco(t_lista_discos *list_disco, int id_disco){
	t_lista_discos *ptr, *ptr2;


	if(list_disco == NULL){
		return NULL;
	}else{
		ptr = list_disco;
		while((ptr->sgte != NULL) && (ptr->id_disco != id_disco)){
			ptr2 = ptr;
			ptr = ptr->sgte;
		}

		if(ptr->lecturas_pendientes != 0){
			reasignar_cola_lecturas(list_disco, ptr->cola_lectura);
		}

		ptr2->sgte = ptr->sgte;
		free(ptr);
	}

	return 0;
}

/**** Proceso de comunicación del RAID con PFS y PPD ****/

void comunicacion(t_lista_discos *list_disco, t_nipc paquete){
	t_lista_discos *discoElegido;
	int id_disco = 0;


	if("llega un nuevo disco"){
		agregar_disco(list_disco, paquete);
	}

	if(paquete ->tipo_solicitud == 'R'){
		discoElegido = buscar_disco_menos_solicitado(list_disco);
		agregar_solicitud(discoElegido->cola_lectura, paquete);
	}

	if(paquete ->tipo_solicitud == 'W'){
		agregar_escritura(list_disco, paquete);
	}

	if("se cae un disco"){
		remover_disco(list_disco, id_disco);
	}


}



